#include "Memory.h"
#include "PageReplacementManager.h"

Memory::Memory(const int pageSize, const int userPages, int kernelPages, bool disk)
{
	isDisk = disk;
	m_PageSize = pageSize;
	m_pages = new PAGES[2];
	m_UserPages = userPages;
	m_KernelPages = kernelPages;
	m_pages[KERNEL].reserve(kernelPages);
	m_pages[USER].reserve(userPages);
	m_availablePages = new list<int>[2];
	for(int i=0 ; i<userPages ; i++)
	{
		m_pages[USER][i].data = new byte[pageSize]; 
		m_pages[USER][i].pid = -1;
		m_pages[USER][i].id = -1;
		m_availablePages[USER].push_back(i);
	}
	for(int i=0 ; i<kernelPages ; i++)
	{
		m_pages[KERNEL][i].data = new byte[pageSize]; 
		m_pages[KERNEL][i].pid = -1;
		m_pages[KERNEL][i].id = -1;
		m_availablePages[KERNEL].push_back(i);
	}
}

Memory::~Memory(void)
{
	delete[] m_availablePages;
	delete[] m_pages;
}

void Memory::setPRM(PageReplacementManager* PRM)
{
	m_PRM = PRM;
}

int Memory::allocate(int place, int id, int pid)
{
	if(m_availablePages[place].size() == 0) return -1;
	int i = m_availablePages[place].front();
	m_availablePages[place].pop_front();	
	m_pages[place][i].id = id;
	m_pages[place][i].pid = pid;
	return i;
}

void Memory::free(int index, int place)
{
	m_availablePages[place].push_back(index);
	m_pages[place][index].id = -1;
	m_pages[place][index].pid = -1;
	if(!isDisk)
	{
		m_PRM->removeFIFO(place, index);
	}
}

byte* Memory::read(int place, int page, int offset, int pTime)
{
	m_pages[place][page].reference = true;
	m_pages[place][page].referenceTime = pTime;

	return &m_pages[place][page].data[offset];
}

void Memory::write(int place, int page, int offset, const byte* data, int ammount, int pTime)
{
	m_pages[place][page].dirty = true;
	m_pages[place][page].reference = true;
	m_pages[place][page].referenceTime = pTime;

	for(int i=0;i<ammount;i++)
	{
		m_pages[place][page].data[offset + i] = data[i];
	}
}

void Memory::replace(int place, int page, Page* what)
{
	for(int i=0 ; i<m_PageSize ; i++)
	{
		m_pages[place][page].data[i] = what->data[i];
	}
	m_pages[place][page].reference = what->reference;
	m_pages[place][page].referenceTime = what->referenceTime;
	m_pages[place][page].dirty = what->dirty;
	m_pages[place][page].id = what->id;
	m_pages[place][page].pid = what->pid;
}

void Memory::printUser()
{
	cout << "User Main Memory" << endl;
	for(int i=0 ; i<m_UserPages ; i++)
	{
		Page* page = &m_pages[USER][i];
		cout << "(" ;
		if(page->pid == -1)
		{
			cout << "empty";
		}
		else
		{
			cout << page->pid << " , " << (page->id * m_PageSize);
		}
		cout << ")" << endl;
	}
}

void Memory::printKernel()
{
	cout << "Kernel Main Memory" << endl;
	for(int i=0 ; i<m_KernelPages; i++)
	{
		Page* page = &m_pages[KERNEL][i];
		cout << "(" ;
		if(page->pid == -1)
		{
			cout << "empty";
		}
		else
		{
			cout << page->pid << " , " << (page->id * m_PageSize);
		}
		cout << ")" << endl;
	}
}
